#ifndef __NTEST_HEADER__
#define __NTEST_HEADER__




#ifndef NULL
	#define NULL		0
#endif

struct NTestUnitBase
{
	virtual void run() = 0;
	virtual const char * name() const = 0;
	virtual int index() const = 0;
};

NTestUnitBase *		NCreateTestUnitApp(const char * InName, int InIdx);
void				NDeleteTestUnitApp(NTestUnitBase * InUnit);

template<typename UnitT>
struct NTestUnit : public NTestUnitBase
{
	static UnitT * Instance() {
		static UnitT ins;
		return &ins;
	}

	NTestUnit(const char * InName, int InIdx):mUnitBase(NULL)
	{
		mUnitBase = NCreateTestUnitApp(InName, InIdx);
	}

	~NTestUnit()
	{
		if (mUnitBase)
		{
			NDeleteTestUnitApp(mUnitBase);
			mUnitBase = NULL;
		}
	}

	virtual const char * name() const {
		return mUnitBase->name();
	} 

	virtual int index() const {
		return mUnitBase->index();
	}
protected:
	NTestUnitBase * mUnitBase;
};

struct NTestFuncsBase
{
	virtual void run() = 0;
	virtual const char * name() const = 0;
};

NTestFuncsBase *	NCreateTestFuncsApp(const char * InName);
void				NDeleteTestFuncsApp(NTestFuncsBase * InFuncs);

class NTestFuncs : public NTestFuncsBase
{
public:
	NTestFuncs(const char * InName):mFuncsBase(NULL)
	{
		mFuncsBase = NCreateTestFuncsApp(InName);		
	}
	virtual ~NTestFuncs()
	{
		if (mFuncsBase)
		{
			NDeleteTestFuncsApp(mFuncsBase);
			mFuncsBase = NULL;
		}
	}

	const char * name() const { return mFuncsBase->name(); }

protected:
	NTestFuncsBase * mFuncsBase;
};

struct NTestCaseBase
{
	virtual void setup() = 0;
	virtual void close() = 0;
	virtual bool pause() = 0;
	virtual void addFuncs(NTestFuncsBase * InFuncs) = 0;
	virtual const char * name() const = 0;
	virtual void setName(const char * InName) = 0;
	virtual void run() = 0;
};

NTestCaseBase *		NCreateTestCaseApp();
void				NDeleteTestCaseApp(NTestCaseBase * InCase);

struct NTestHostBase
{
	virtual int addCase(NTestCaseBase * InCase, const char * InName) = 0;
	virtual int addCase(NTestCaseBase * InCase, const char * InName, int InId) = 0;
	virtual int addUnit(NTestUnitBase * InUnit) = 0;
	virtual void run(const char * InCmd) = 0;
};

NTestHostBase *		NCreateTestHostApp();
void				NDeleteTestHostApp(NTestHostBase * InHost);

template<typename CaseT>
class NTestCase : public NTestCaseBase
{
protected:
	typedef typename	CaseT		TestCaseType;

	
public:
	NTestCase()
		:mCaseBase(NULL)
	{	
		mCaseBase = NCreateTestCaseApp();
	}
	
	virtual ~NTestCase()
	{
		if (mCaseBase)
		{
			NDeleteTestCaseApp(mCaseBase);
			mCaseBase = NULL;
		}
	}

	static TestCaseType * Instance()
	{
		static TestCaseType Ins;
		return &Ins;
	}

	void addFuncs(NTestFuncsBase * InFuncs)
	{
		mCaseBase->addFuncs(InFuncs);
	}

	const char * name() const { return mCaseBase->name(); }

	void setName(const char * InName) { mCaseBase->setName(InName); }

	void run() { mCaseBase->run(); }

	void setup() {}

	void close() {}

	bool pause() { return false; }
protected:

	friend class NTestHost;

	NTestCaseBase *		mCaseBase;
};

class NTestHost : public NTestHostBase
{
public:
	NTestHost()
		:mHostBase(NULL)
	{
		mHostBase = NCreateTestHostApp();
	}

	~NTestHost()
	{
		if (mHostBase)
		{
			NDeleteTestHostApp(mHostBase);
			mHostBase = NULL;
		}
	}

	static NTestHost * Instance()
	{
		static NTestHost Ins;
		return &Ins;
	}

	int addCase(NTestCaseBase * InCase, const char * InName)
	{
		return mHostBase->addCase(InCase, InName);
	}

	int addCase(NTestCaseBase * InCase, const char * InName, int InId)
	{
		return mHostBase->addCase(InCase, InName, InId);
	}

	int addUnit(NTestUnitBase * InUnit)
	{
		return mHostBase->addUnit(InUnit);
	}

	void run(const char * InCmd = 0)
	{
		mHostBase->run(InCmd);
	}

private:
	NTestHostBase * mHostBase;
};

#define NCASE(InName) \
	struct InName : public NTestCase<InName>

#define NTEST(InName) \
	struct NTestFuncs_##InName : public NTestFuncs\
	{\
		NTestFuncs_##InName():NTestFuncs(#InName)\
		{\
			TestCaseType::Instance()->addFuncs(this);\
		}\
		void run()\
		{\
			TestCaseType::Instance()->InName();\
		}\
	};\
	NTestFuncs_##InName TestFuncsInstance_##InName;\
	void InName()


#define NREG(InName, InId) \
	int TestCaseRegister_##InName = NTestHost::Instance()->addCase(InName::Instance(), #InName, InId);
	

#define NADD(InName) \
	int TestCaseRegister_##InName = NTestHost::Instance()->addCase(InName::Instance(), #InName);


// unit represent a test unit that will run directly(not wrap by test cases)
#define NUNIT(InName, InIdx)									\
	struct InName : public NTestUnit<InName>					\
	{															\
		InName():NTestUnit<InName>(#InName, InIdx) {}			\
		virtual void run();										\
	};															\
	int TestUnitRegister_##InName =								\
		NTestHost::Instance()->addUnit(InName::Instance());		\
	void InName::run()


#define NRUN(InCmd)		NTestHost::Instance()->run(InCmd);

void NLogf(const char * InMsg, ...);
void NLogf(const wchar_t * InMsg, ...);
	
#define NLOG			NLogf

#define NMSGBOX

void NPause();
void NPause(const char * InMsg, ...);
void NPause(const wchar_t * InMsg, ...);

#define NPAUSE			NPause

bool NStrEqual(const char * InA, const char * InB);
bool NStrEqual(const wchar_t * InA, const wchar_t * InB);

bool NStrSame(const char * InA, const char * InB);
bool NStrSame(const wchar_t * InA, const wchar_t * InB);

template<typename T>
bool NArrayEqual(const T InA[], const T InB[], int InNum)
{
	for (int i = 0; i < InNum; ++i)
	{
		if (InA[i] != InB[i])
		{
			return false;
		}
	}
	return true;
}

template<typename T>
bool NArraySame(const T InA[], const T InB[], int InNum)
{

	return false;
}

bool NFloatEqual(double InValue, double InEq);

#define NCHECK(v)		((!!(v))||(*(int *)0x00000000 = 0x01))
#define NTRUE(v)		NCHECK(v)
#define NFALSE(v)		NCHECK(!(v))
#define NEQ(a, b)		NCHECK((a) == (b))
#define NNE(a, b)		NCHECK((a) != (b))
#define NLT(a, b)		NCHECK((a) < (b))
#define NLE(a, b)		NCHECK((a) <= (b))
#define NGT(a, b)		NCHECK((a) > (b))
#define NGE(a, b)		NCHECK((a) >= (b))

#define NFEQ(a, b)		NCHECK(NFloatEqual(a, b))

#define NSTREQ(a, b)	NCHECK(NStrEqual(a, b))
#define NSTRNE(a, b)	NCHECK(!NStrEqual(a, b))
#define NSTRSM(a, b)	NCHECK(NStrSame(a, b))
#define NSTRNS(a, b)	NCHECK(!NStrSame(a, b))

#define NARRAYEQ(a, b, num)		NCHECK(NArrayEqual(a, b, num))
#define NARRAYNE(a, b, num)		NCHECK(!NArrayEqual(a, b, num))
#define NARRAYSM(a, b, num)
#define NARRAYNS(a, b, num)


#include "NCrash.h"
#include "NPerformance.h"


#endif //__NTEST_HEADER__